package com.idea.relax.exception.alarm;

import com.idea.relax.exception.api.BaseException;
import com.idea.relax.exception.api.IErrorCode;
import com.idea.relax.exception.api.IErrorLevel;
import com.idea.relax.exception.api.IErrorType;
import com.idea.relax.exception.config.ExceptionKitProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Map;
import java.util.Set;

/**
 * @className: ErrorAlarmEventPublisher
 * @description: 异常告警时间的发布器
 * @author: salad
 * @date: 2023/2/28
 **/
@Slf4j
@Component
public class ErrorAlarmEventPublisher implements ApplicationEventPublisherAware {

	private static ApplicationEventPublisher publisher;

	/**
	 * 发布告警事件
	 *
	 * @param e BaseException异常类
	 * @param properties 配置类
	 */
	public static void alarmIfAllow(BaseException e, ExceptionKitProperties properties) {
		if (properties.isAlarm()) {
			if (CollectionUtils.isEmpty(properties.getAlarmLevels())) {
				return;
			}
			Map<ExceptionKitProperties.AlarmType, Set<String>> alarmLevels = properties.getAlarmLevels();
			boolean alarmed = ErrorAlarmEventPublisher.ifAllow(e, alarmLevels);
			if (alarmed) {
				ErrorAlarmEventPublisher.publish(e.getErrorLevel(), e.getErrorType(), e.getErrorCodeEnum());
			}
		}
	}

	/**
	 * 是否允许告警
	 * @param e BaseException异常类
	 * @param alarmLevels 是否允许告警的相关配置
	 * @return 是否允许告警
	 */
	private static boolean ifAllow(BaseException e, Map<ExceptionKitProperties.AlarmType, Set<String>> alarmLevels) {
		boolean alarmed = false;
		Set<ExceptionKitProperties.AlarmType> alarmTypes = alarmLevels.keySet();
		for (ExceptionKitProperties.AlarmType alarmType : alarmTypes) {
			if (alarmed) {
				return true;
			}
			switch (alarmType) {
				case ERROR_LEVEL:
					for (String name : alarmLevels.get(alarmType)) {
						if (e.getErrorLevel().getLevel().equals(name)) {
							alarmed = true;
							break;
						}
					}
					break;
				case ERROR_CODE:
					for (String code : alarmLevels.get(alarmType)) {
						if (e.getErrorCode().equals(code)) {
							alarmed = true;
							break;
						}
					}
					break;
				case EXCEPTION_NAME:
					for (String name : alarmLevels.get(alarmType)) {
						if (e.getClass().getName().equals(name)) {
							alarmed = true;
							break;
						}
					}
					break;
				case EXCEPTION_PACKAGE:
					for (String name : alarmLevels.get(alarmType)) {
						if (e.getClass().getPackage().getName().equals(name)) {
							alarmed = true;
							break;
						}
					}
					break;
				case ERROR_CODE_NAME:
					for (String name : alarmLevels.get(alarmType)) {
						if (e.getErrorCodeEnum().getClass().getSimpleName().equals(name)) {
							alarmed = true;
							break;
						}
					}
					break;
				default:
					for (String name : alarmLevels.get(alarmType)) {
						if (e.getErrorCodeEnum().getClass().getName().equals(name)) {
							alarmed = true;
							break;
						}
					}
			}
		}
		return alarmed;
	}

	/**
	 * 发布异常告警事件，高、中等级的时候会发布
	 *
	 * @param errorLevel 异常等级
	 * @param errorCode  异常码
	 */
	public static void publish(IErrorLevel errorLevel, IErrorType errorType, IErrorCode errorCode) {
		ErrorMetadata errorMetadata = new ErrorMetadata();
		errorMetadata.setErrorLevel(errorLevel);
		errorMetadata.setErrorType(errorType);
		errorMetadata.setErrorCode(errorCode);
		publish(new ErrorAlarmEvent(errorMetadata));
	}


	private static void publish(ErrorAlarmEvent event) {
		if (publisher != null) {
			try {
				publisher.publishEvent(event);
			} catch (Exception e) {
				log.error("Failed to publish the log event,event name:[" + event.getClass().getSimpleName() + "]", e);
				throw e;
			}
		}
	}

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		ErrorAlarmEventPublisher.publisher = publisher;
	}


}
